package top.chmin.project.cloud.common.entity.column.auto;

// field import auto
// #bind.field.fieldCode#

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import top.chmin.project.cloud.common.entity.Page;
import top.chmin.project.cloud.common.entity.auto.Entity;
import top.chmin.project.cloud.common.entity.auto.EntityDao;
import top.chmin.project.cloud.common.entity.auto.EntityFPC;
import top.chmin.project.cloud.common.tool.DatetimeTool;
import top.chmin.project.cloud.common.tool.LocalTool;

import java.time.LocalDateTime;
import java.util.List;

/**
 * chmin
 * 2023-12-26 20:07:58
 * cloud-builder
 */
@Slf4j
@Component
public class EntityColumnPlugin {

    @Resource
    EntityDao entityDao;
    @Resource
    EntityColumnDao entityColumnDao;
    @Resource
    JdbcTemplate template;

    public void checkSave(EntityColumnSave.Param param) {
        log.debug("checkSave-param: {}", JSONUtil.toJsonStr(param));
        if (param == null) {
            throw new RuntimeException("保存对象不能为空");
        }
    }

    private void fillSave(EntityColumn entityColumn) {
        entityColumn.setCreateBy(LocalTool.getUserId());
        entityColumn.setUpdateBy(LocalTool.getUserId());
        entityColumn.setCreateTime(LocalDateTime.now());
        entityColumn.setUpdateTime(LocalDateTime.now());

        if (StringUtils.isEmpty(entityColumn.getColumnNullable())) {
            entityColumn.setColumnNullable("NULL");
        }
        if (StringUtils.isEmpty(entityColumn.getColumnName())) {
            entityColumn.setColumnName(StrUtil.toUnderlineCase(entityColumn.getFieldName()));
        }
        if (StringUtils.isEmpty(entityColumn.getMethodName())) {
            entityColumn.setMethodName(StringUtils.capitalize(entityColumn.getFieldName()));
        }
        switch (entityColumn.getColumnType()) {
            case "VARCHAR": {
                if (entityColumn.getColumnLength() == null) {
                    entityColumn.setColumnLength(32);
                }
                if (StringUtils.isEmpty(entityColumn.getSimpleType())) {
                    entityColumn.setSimpleType("String");
                }
                if (StringUtils.isEmpty(entityColumn.getFullType())) {
                    entityColumn.setFullType("java.lang.String");
                }
                break;
            }
            case "DECIMAL": {
                if (entityColumn.getColumnPrecision() == null) {
                    entityColumn.setColumnPrecision(6);
                }
                if (entityColumn.getColumnScale() == null) {
                    entityColumn.setColumnScale(2);
                }
                if (StringUtils.isEmpty(entityColumn.getSimpleType())) {
                    entityColumn.setSimpleType("BigDecimal");
                }
                if (StringUtils.isEmpty(entityColumn.getFullType())) {
                    entityColumn.setFullType("java.math.BigDecimal");
                }
            }
            case "INT": {
                if (StringUtils.isEmpty(entityColumn.getSimpleType())) {
                    entityColumn.setSimpleType("Integer");
                }
                if (StringUtils.isEmpty(entityColumn.getFullType())) {
                    entityColumn.setFullType("java.lang.Integer");
                }
            }
            case "BIGINT": {
                if (StringUtils.isEmpty(entityColumn.getSimpleType())) {
                    entityColumn.setSimpleType("Long");
                }
                if (StringUtils.isEmpty(entityColumn.getFullType())) {
                    entityColumn.setFullType("java.lang.Long");
                }
            }
            case "DATETIME": {
                if (StringUtils.isEmpty(entityColumn.getSimpleType())) {
                    entityColumn.setSimpleType("LocalDateTime");
                }
                if (StringUtils.isEmpty(entityColumn.getFullType())) {
                    entityColumn.setFullType("java.time.LocalDateTime");
                }
            }
        }
        if (entityColumn.getDataOrder() == null) {
            entityColumn.setDataOrder(0);
        }
        if (entityColumn.getSearchOrder() == null) {
            entityColumn.setSearchOrder(0);
        }
        if (entityColumn.getFormOrder() == null) {
            entityColumn.setFormOrder(0);
        }
        if (entityColumn.getPageColumnOrder() == null) {
            entityColumn.setPageColumnOrder(0);
        }
        if (StringUtils.isEmpty(entityColumn.getSearchExist())) {
            entityColumn.setSearchExist("Y");
        }
        if (StringUtils.isEmpty(entityColumn.getSaveExist())) {
            entityColumn.setSaveExist("Y");
        }
        if (StringUtils.isEmpty(entityColumn.getUpdateExist())) {
            entityColumn.setUpdateExist("Y");
        }
        if (StringUtils.isEmpty(entityColumn.getDetailExist())) {
            entityColumn.setDetailExist("Y");
        }
        if (StringUtils.isEmpty(entityColumn.getPageColumnExist())) {
            entityColumn.setPageColumnExist("Y");
        }
    }

    public void beforeSave(EntityColumn entityColumn) {
        log.debug("beforeSave-entityColumn: {}", JSONUtil.toJsonStr(entityColumn));
        fillSave(entityColumn);

        if (entityColumnDao.countByCondition(entityColumn.getPreCondition().forCount().tableCode().eq().toCondition()) == 0) {
            // 插入通用字段
            EntityColumn id = new EntityColumn()
                    .setTableCode(entityColumn.getTableCode())
                    .setFieldName("id")
                    .setColumnType("BIGINT")
                    .setColumnNullable("NOT NULL")
                    .setRemark("ID");
            id.setCreateBy(LocalTool.getUserId());
            id.setUpdateBy(LocalTool.getUserId());
            id.setCreateTime(LocalDateTime.now());
            id.setUpdateTime(LocalDateTime.now());
            fillSave(id);
            entityColumnDao.save(id);

            EntityColumn createBy = new EntityColumn()
                    .setTableCode(entityColumn.getTableCode())
                    .setFieldName("createBy")
                    .setColumnType("VARCHAR")
                    .setColumnNullable("NOT NULL")
                    .setRemark("创建人");
            fillSave(createBy);
            entityColumnDao.save(createBy);

            EntityColumn updateBy = new EntityColumn()
                    .setTableCode(entityColumn.getTableCode())
                    .setFieldName("updateBy")
                    .setColumnType("VARCHAR")
                    .setColumnNullable("NOT NULL")
                    .setRemark("修改人");
            fillSave(updateBy);
            entityColumnDao.save(updateBy);

            EntityColumn createTime = new EntityColumn()
                    .setTableCode(entityColumn.getTableCode())
                    .setFieldName("createTime")
                    .setColumnType("DATETIME")
                    .setColumnNullable("NOT NULL")
                    .setRemark("创建时间");
            fillSave(createTime);
            entityColumnDao.save(createTime);

            EntityColumn updateTime = new EntityColumn()
                    .setTableCode(entityColumn.getTableCode())
                    .setFieldName("updateTime")
                    .setColumnType("DATETIME")
                    .setColumnNullable("NOT NULL")
                    .setRemark("修改时间");
            fillSave(updateTime);
            entityColumnDao.save(updateTime);

            Entity entity = entityDao.getFirst(
                    new EntityFPC()
                            .tableCode().eq(entityColumn.getTableCode())
                            .toCondition()
            );

            // 生成表
            template.execute("""
                    CREATE TABLE %s (
                        id BIGINT AUTO_INCREMENT COMMENT 'ID' PRIMARY KEY,
                        create_by VARCHAR(32) NOT NULL COMMENT '创建人',
                        create_time DATETIME NOT NULL COMMENT '创建时间',
                        update_by VARCHAR(32) NOT NULL COMMENT '更新人',
                        update_time DATETIME NOT NULL COMMENT '更新时间'
                    ) COMMENT '%s';
                    """.formatted(
                    entity.getTableName(),
                    entity.getRemark()
            ));

            // TODO save
        }
    }

    public void afterSave(EntityColumnSave.Param param, EntityColumn entityColumn, int result) {
        log.debug("afterSave-param: {}", JSONUtil.toJsonStr(param));
        log.debug("afterSave-entityColumn: {}", JSONUtil.toJsonStr(entityColumn));
        log.debug("afterSave-result: {}", JSONUtil.toJsonStr(result));

        Entity entity = entityDao.getFirst(
                new EntityFPC()
                        .tableCode().eq(entityColumn.getTableCode())
                        .toCondition()
        );

        switch (entityColumn.getColumnType()) {
            case "VARCHAR": {
                template.execute("ALTER TABLE %s ADD COLUMN %s VARCHAR(%s) %s COMMENT '%s';".formatted(
                        entity.getTableName(),
                        entityColumn.getColumnName(),
                        entityColumn.getColumnLength(),
                        entityColumn.getColumnNullable(),
                        entityColumn.getRemark())
                );
                break;
            }
            case "DECIMAL": {
                template.execute("ALTER TABLE %s ADD COLUMN %s DECIMAL(%s, %s) %s COMMENT '%s';".formatted(
                        entity.getTableName(),
                        entityColumn.getColumnName(),
                        entityColumn.getColumnPrecision(),
                        entityColumn.getColumnScale(),
                        entityColumn.getColumnNullable(),
                        entityColumn.getRemark())
                );
                break;
            }
            default: {
                template.execute("ALTER TABLE %s ADD COLUMN %s %s %s COMMENT '%s';".formatted(
                        entity.getTableName(),
                        entityColumn.getColumnName(),
                        entityColumn.getColumnType(),
                        entityColumn.getColumnNullable(),
                        entityColumn.getRemark())
                );
            }
        }
    }

    public void checkUpdateById(EntityColumnUpdateById.Param param) {
        log.debug("checkUpdateById-param: {}", JSONUtil.toJsonStr(param));
        if (param == null) {
            throw new RuntimeException("更新对象不能为空");
        }
        if (param.getId() == null) {
            throw new RuntimeException("更新对象id不能为空");
        }
    }

    public void beforeUpdateById(EntityColumn entityColumn) {
        log.debug("beforeUpdateById-entityColumn: {}", JSONUtil.toJsonStr(entityColumn));
        entityColumn.setUpdateBy(LocalTool.getUserId());
        entityColumn.setUpdateTime(LocalDateTime.now());
    }

    public void afterUpdateById(EntityColumnUpdateById.Param param, EntityColumn entityColumn, int result) {
        log.debug("afterUpdateById-param: {}", JSONUtil.toJsonStr(param));
        log.debug("afterUpdateById-entityColumn: {}", JSONUtil.toJsonStr(entityColumn));
        log.debug("afterUpdateById-result: {}", JSONUtil.toJsonStr(result));

    }

    public void checkDeleteById(EntityColumnDeleteById.Param param) {
        log.debug("checkDeleteById-param: {}", JSONUtil.toJsonStr(param));
        if (param == null) {
            throw new RuntimeException("删除对象不能为空");
        }
        if (param.getId() == null) {
            throw new RuntimeException("删除对象id不能为空");
        }
    }

    public void afterDeleteById(EntityColumnDeleteById.Param param, int result) {
        log.debug("afterDeleteById-param: {}", JSONUtil.toJsonStr(param));
        log.debug("afterDeleteById-result: {}", JSONUtil.toJsonStr(result));

    }

    public void checkSelectById(EntityColumnSelectById.Param param) {
        log.debug("checkSelectById-param: {}", JSONUtil.toJsonStr(param));
        if (param == null) {
            throw new RuntimeException("查询对象不能为空");
        }
        if (param.getId() == null) {
            throw new RuntimeException("查询对象id不能为空");
        }
    }

    public void beforeSelectById(EntityColumnSelectById.Param param, EntityColumnFPC fpc) {
        log.debug("beforeSelectById-param: {}", JSONUtil.toJsonStr(param));

    }

    public void afterSelectById(EntityColumnSelectById.Param param, EntityColumnSelectById.Result result) {
        log.debug("afterSelectById-param: {}", JSONUtil.toJsonStr(param));
        log.debug("afterSelectById-result: {}", JSONUtil.toJsonStr(result));

    }

    public void checkSelectPage(EntityColumnSelectPage.Param param) {
        log.debug("checkSelectPage-param: {}", JSONUtil.toJsonStr(param));
        if (param == null) {
            throw new RuntimeException("分页对象不能为空");
        }
    }

    public void beforeSelectPage(EntityColumnSelectPage.Param param, EntityColumnFPC fpc) {
        log.debug("beforeSelectPage-param: {}", JSONUtil.toJsonStr(param));
// field beforeSelectPage auto
// #bind.field.fieldCode#
        fpc.fieldCode().eq(param.getFieldCode());
// $bind.field.fieldCode$

// #bind.field.createBy#
        fpc.createBy().eq(param.getCreateBy());
// $bind.field.createBy$

// #bind.field.updateBy#
        fpc.updateBy().eq(param.getUpdateBy());
// $bind.field.updateBy$

// #bind.field.createTime#
        fpc.createTime().ge(param.getCreateTime() == null || param.getCreateTime().length == 0 ? null : param.getCreateTime()[0]);
        fpc.createTime().lt(param.getCreateTime() == null || param.getCreateTime().length < 2 ? null : DatetimeTool.nextDay(param.getCreateTime()[1]));
// $bind.field.createTime$

// #bind.field.updateTime#
        fpc.updateTime().ge(param.getUpdateTime() == null || param.getUpdateTime().length == 0 ? null : param.getUpdateTime()[0]);
        fpc.updateTime().lt(param.getUpdateTime() == null || param.getUpdateTime().length < 2 ? null : DatetimeTool.nextDay(param.getUpdateTime()[1]));
// $bind.field.updateTime$

// #bind.field.tableCode#
        fpc.tableCode().eq(param.getTableCode());
// $bind.field.tableCode$

// #bind.field.columnType#
        fpc.columnType().eq(param.getColumnType());
// $bind.field.columnType$

// #bind.field.columnLength#
        fpc.columnLength().eq(param.getColumnLength());
// $bind.field.columnLength$

// #bind.field.columnPrecision#
        fpc.columnPrecision().eq(param.getColumnPrecision());
// $bind.field.columnPrecision$

// #bind.field.columnScale#
        fpc.columnScale().eq(param.getColumnScale());
// $bind.field.columnScale$

// #bind.field.columnNullable#
        fpc.columnNullable().eq(param.getColumnNullable());
// $bind.field.columnNullable$

// #bind.field.fieldName#
        fpc.fieldName().eq(param.getFieldName());
// $bind.field.fieldName$

// #bind.field.columnName#
        fpc.columnName().eq(param.getColumnName());
// $bind.field.columnName$

// #bind.field.methodName#
        fpc.methodName().eq(param.getMethodName());
// $bind.field.methodName$

// #bind.field.simpleType#
        fpc.simpleType().eq(param.getSimpleType());
// $bind.field.simpleType$

// #bind.field.fullType#
        fpc.fullType().eq(param.getFullType());
// $bind.field.fullType$

// #bind.field.remark#
        fpc.remark().eq(param.getRemark());
// $bind.field.remark$

// #bind.field.dataOrder#
        fpc.dataOrder().eq(param.getDataOrder());
// $bind.field.dataOrder$

// #bind.field.searchOrder#
        fpc.searchOrder().eq(param.getSearchOrder());
// $bind.field.searchOrder$

// #bind.field.formOrder#
        fpc.formOrder().eq(param.getFormOrder());
// $bind.field.formOrder$

// #bind.field.pageColumnOrder#
        fpc.pageColumnOrder().eq(param.getPageColumnOrder());
// $bind.field.pageColumnOrder$

// #bind.field.searchExist#
        fpc.searchExist().eq(param.getSearchExist());
// $bind.field.searchExist$

// #bind.field.saveExist#
        fpc.saveExist().eq(param.getSaveExist());
// $bind.field.saveExist$

// #bind.field.updateExist#
        fpc.updateExist().eq(param.getUpdateExist());
// $bind.field.updateExist$

// #bind.field.detailExist#
        fpc.detailExist().eq(param.getDetailExist());
// $bind.field.detailExist$

// #bind.field.pageColumnExist#
        fpc.pageColumnExist().eq(param.getPageColumnExist());
// $bind.field.pageColumnExist$

    }

    public void afterSelectPage(EntityColumnSelectPage.Param param, Page<EntityColumnSelectPage.Result> result) {
        log.debug("afterSelectPage-param: {}", JSONUtil.toJsonStr(param));
        log.debug("afterSelectPage-result: {}", JSONUtil.toJsonStr(result));

    }

    // entity select auto

    public void checkSelectFieldCode(EntityColumnFieldCodeSelect.Param param) {
        log.debug("checkSelectFieldCode-param: {}", JSONUtil.toJsonStr(param));
    }

    public void beforeSelectFieldCode(EntityColumnFieldCodeSelect.Param param, EntityColumnFPC fpc) {
        log.debug("beforeSelectFieldCode-param: {}", JSONUtil.toJsonStr(param));
        log.debug("beforeSelectFieldCode-fpc: {}", JSONUtil.toJsonStr(fpc));

    }

    public void afterSelectFieldCode(EntityColumnFieldCodeSelect.Param param, List<EntityColumnFieldCodeSelect.Result> result) {
        log.debug("afterSelectFieldCode-param: {}", JSONUtil.toJsonStr(param));
        log.debug("afterSelectFieldCode-result: {}", JSONUtil.toJsonStr(result));

    }


// entity search auto
}
